/*!
//      
//      \file	k2k_StateHandlerCln.c
//      
//      \author	Copyright 2010 Valentina Vuksic <vuksv1@bfh.ch>, Beat Liechti <liecb2@bfh.ch>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.
//
//      Abstract Data Type for the state handler of the state "Cln" (Maintenance of the coffee machine)
//      
//      \brief		CAS-EBX-03 Projektarbeit 
//      			Valentina Vuksic (VUKSV1), Beat Liechti (LIECB2)
//      			StateHandlerMlkC ADT for the k2k (Kaffee2000) application
//      \version	1.0
//      \date		2010-05-02
//      \remark		Last Modifications:
//      \remark  	v1.0, VUKSV1/LIECB2, 2010-05-02 Initial release
//
*/

#include <stdio.h>
#include <unistd.h>
#include "k2k_IO.h"
#include "k2k_StateHandlerCln.h"
#include "k2k_AudioPlayer.h"

#define STATE_TEXT	"Cleaning k2k - please wait"
#define HUNDRETH_SECOND	10000
#define TINY_PAUSE		2*HUNDRETH_SECOND

/* -- static function declarations -----------------------------------*/

static k2k_State k2k_StateHandlerCln_Handler(k2k_Event event, k2k_State previousState, k2k_StateHandlerData *handlerData);
static void k2k_StateHandlerCln_SignalHandler(int sigNo, void *customData);

/* -- ADT functions --------------------------------------------------*/

/*!
//
// Creates StateHandlerCln ADT "object"
//
// \param stateMachine is the pointer to the StateMachine structure
// 
// \return pointer to the StateHandlerCln ADT
//
*/
k2k_StateHandlerCln* k2k_StateHandlerCln_Create(k2k_StateMachine *stateMachine, k2k_IO *IO)
{
	k2k_StateHandlerCln *stateHandlerCln = NULL;
	stateHandlerCln = malloc(sizeof(k2k_StateHandlerCln));
	if (stateHandlerCln != NULL)
	{
		/*! initialize structure */		
		stateHandlerCln->handler = k2k_StateHandlerCln_Handler;	
		stateHandlerCln->IO = IO;
		/*! setup signaling */
		stateHandlerCln->signal = k2k_Signal_Create(k2k_SIG_CLN, k2k_StateHandlerCln_SignalHandler, stateHandlerCln);
		if (stateHandlerCln->signal == NULL)
		{
			stateHandlerCln->err = k2k_STATEHANDLER_ERR_CREATE_SIGNAL_FAILED;
		}
		else
		{
			/*! reset signal variable */
			stateHandlerCln->sigNo = 0;
			/*! create state handler data */
			stateHandlerCln->handlerData = k2k_StateHandlerData_Create(stateHandlerCln);		
			if (stateHandlerCln->handlerData == NULL)
			{
				stateHandlerCln->err = k2k_STATEHANDLER_ERR_CREATE_SIGNAL_FAILED;
			}
			else
			{
				/*! add the state handler to the state machine */
				k2k_StateMachine_AddStateHandler(stateMachine, STATE_CLN, stateHandlerCln->handler, stateHandlerCln->handlerData);
				/*! store reference to state machine */
				stateHandlerCln->stateMachine = stateMachine;
				/*! flag success */
				stateHandlerCln->err = k2k_STATEHANDLER_ERR_SUCCESS;
			}
		}
	}
	return stateHandlerCln;
}

/*!
//
// Releases StateHandlerCln ADT "object"
// 
// \param StateHandlerCln is the pointer to the StateHandlerCln structure 
// 
// \return nothing
//
*/
void k2k_StateHandlerCln_Release(k2k_StateHandlerCln *stateHandlerCln)
{
	if (stateHandlerCln != NULL)
	{	
		if (stateHandlerCln->signal != NULL)
		{
			/*! release signal ADT */
			k2k_Signal_Release(stateHandlerCln->signal);
			stateHandlerCln->signal = NULL;
		}
		if (stateHandlerCln->handlerData != NULL)
		{
			/*! release handler data */
			k2k_StateHandlerData_Release(stateHandlerCln->handlerData);
			stateHandlerCln->handlerData = NULL;
		}
		/*! release memory */
		free(stateHandlerCln);	
	}
}

/* -- static functions -----------------------------------------------*/

/*!
//
// Actual state handler for the state "Cln"
//
// \param event describes the event that happened
// \param customData points to custom data (typically the corresponding ADT struct)
//
// \return next state of the event machine
//
*/
static k2k_State k2k_StateHandlerCln_Handler(k2k_Event event, k2k_State previousState, k2k_StateHandlerData *handlerData)
{
	/*! get the state handler structure */
	k2k_StateHandlerCln *stateHandlerCln = handlerData->customData;

	if (previousState != STATE_CLN)
	{
		printf("Cleaning...\n");
							
		/*! set state text */
		k2k_NanoX_ShowStateText(stateHandlerCln->stateMachine->nanoX, STATE_TEXT);
	
		/*! reset blink counter */
		stateHandlerCln->blinkCounter = 0;
		
		/*! reset signal variable */
		stateHandlerCln->sigNo = 0;
		/*! enable signal handler */
		k2k_Signal_Enable(stateHandlerCln->signal);

		/*! play clip while cleaning */		
		k2k_AudioPlaySignal(CLIP_CLN, stateHandlerCln->signal);
	}
	
	/*! blink light randomly */
	k2k_IO_RandomLightShow(stateHandlerCln->IO);

	/*! blink on/off indicator */
	k2k_NanoX_BlinkOnOffButton(stateHandlerCln->stateMachine->nanoX, YELLOW, BLACK, &stateHandlerCln->blinkCounter);
	
	/*! the default is to remain in the same state */	
	int nextState = STATE_CLN;
	switch (event)
	{
		case EVENT_S0: 
			/*! reset LEDS */
			k2k_IO_WriteLed(stateHandlerCln->IO, 0);
			/*! disable signal handler */
			k2k_Signal_Disable(stateHandlerCln->signal);
			/*! go into "Off" state */
			nextState = STATE_OFF;
			break;		
		case EVENT_TIMER:
			/*! check if signal from child process has arrived */
			if (stateHandlerCln->sigNo != 0)
			{
				/*! reset LEDS */
				k2k_IO_WriteLed(stateHandlerCln->IO, 0);
				/*! set state indicator t green */ 
				k2k_NanoX_DrawOnOffButton(stateHandlerCln->stateMachine->nanoX, LTGREEN);
				/*! disable signal handler */
				k2k_Signal_Disable(stateHandlerCln->signal);
				/*! go into "Rdy1" state */
				nextState = STATE_RDY1;
			}
			break;
		default: 
			break;
	}	
	return nextState;
}

/*!
//
// Signal handler for the state "Cln" to synchronize with child process
//
// \param sigNo describes the signal sent by the child process
// \param customData points to custom data (typically the corresponding ADT struct)
//
// \return nothing
//
*/
static void k2k_StateHandlerCln_SignalHandler(int sigNo, void *customData)
{	
	/*! get the state handler */
	k2k_StateHandlerCln *stateHandlerCln = customData;
	stateHandlerCln->sigNo = sigNo;
}
